/*

Copyright (c) 2007 Sunplus Technology Co., Ltd.

Module Name:

		key_scan.c

Abstract:

		Module related to key scan

Environment:

		Keil C51 Compiler

Revision History:

		07/24/2007		Phil	created

*/

//=============================================================================
//Header file
//=============================================================================
#include "general.h"
#include "timer.h"
#include "gpio_api.h"
#include "key_scan.h"
#include "os_msg.h"
#include "app_ui_power.h"
#include "sp1k_util_api.h"

//=============================================================================
//Symbol
//=============================================================================

//-----------------------------------------------------------------------------
//Constant
//-----------------------------------------------------------------------------
#if 0
#define DBG_KEYSCAN
#endif

#define USE_PKG_DEDICATE_PIN  1  /* 0: old code, 1: new code. */

//-----------------------------------------------------------------------------
//Variable
//-----------------------------------------------------------------------------

static UINT16 code keyAdcAValDevTbl[SP1K_ADC_BTN_A_NUM] = {
	SP1K_ADC_BTN_DEV_A_S1,
	SP1K_ADC_BTN_DEV_A_S2,
	SP1K_ADC_BTN_DEV_A_S3,
	SP1K_ADC_BTN_DEV_A_S4,
	SP1K_ADC_BTN_DEV_A_S5,
	SP1K_ADC_BTN_DEV_A_S6,
};

#if (_HW_SOLUTION_ == _HW_EVB_ || _HW_SOLUTION_ == _HW_TK_MODEL_B_)
static UINT16 code keyAdcBValDevTbl[SP1K_ADC_BTN_B_NUM] = {
	SP1K_ADC_BTN_DEV_B_S1,
	SP1K_ADC_BTN_DEV_B_S2,
	SP1K_ADC_BTN_DEV_B_S3,
	SP1K_ADC_BTN_DEV_B_S4,
};
#elif (_HW_SOLUTION_ == _HW_TK_MODEL_A_)
static UINT16 code keyAdcBValDevTbl[SP1K_ADC_BTN_B_NUM] = {
	SP1K_ADC_BTN_DEV_B_S1,
	SP1K_ADC_BTN_DEV_B_S2,
	SP1K_ADC_BTN_DEV_B_S3,
};
#endif

static UINT16 code keyAdcAVal[SP1K_ADC_BTN_A_NUM] = {
	SP1K_ADC_BTN_A_S1,
	SP1K_ADC_BTN_A_S2,
	SP1K_ADC_BTN_A_S3,
	SP1K_ADC_BTN_A_S4,
	SP1K_ADC_BTN_A_S5,
	SP1K_ADC_BTN_A_S6,
};

#if (_HW_SOLUTION_ == _HW_EVB_ || _HW_SOLUTION_ == _HW_TK_MODEL_B_)
static UINT16 code keyAdcBVal[SP1K_ADC_BTN_B_NUM] = {
	SP1K_ADC_BTN_B_S1,
	SP1K_ADC_BTN_B_S2,
	SP1K_ADC_BTN_B_S3,
	SP1K_ADC_BTN_B_S4,
};
#elif (_HW_SOLUTION_ == _HW_TK_MODEL_A_)
static UINT16 code keyAdcBVal[SP1K_ADC_BTN_B_NUM] = {
	SP1K_ADC_BTN_B_S1,
	SP1K_ADC_BTN_B_S2,
	SP1K_ADC_BTN_B_S3,
};
#endif

/*Key message definition*/

static keyMsg_t code keyMsg[SP1K_BTN_NUM] = {

#if (_HW_SOLUTION_ == _HW_EVB_)

	/*ADC A button msg*/
	{SP1K_MSG_KEY_PRESS_RIGHT,		SP1K_MSG_KEY_REPEATE_RIGHT, 	SP1K_MSG_KEY_RELEASE_RIGHT},
	{SP1K_MSG_KEY_PRESS_LEFT, 		SP1K_MSG_KEY_REPEATE_LEFT, 		SP1K_MSG_KEY_RELEASE_LEFT},
	{SP1K_MSG_KEY_PRESS_DOWN, 	SP1K_MSG_KEY_REPEATE_DOWN, 	SP1K_MSG_KEY_RELEASE_DOWN},
	{SP1K_MSG_KEY_PRESS_UP, 		SP1K_MSG_KEY_REPEATE_UP, 		SP1K_MSG_KEY_RELEASE_UP},
	{SP1K_MSG_KEY_PRESS_TELE, 		SP1K_MSG_KEY_REPEATE_TELE, 		SP1K_MSG_KEY_RELEASE_TELE},
	{SP1K_MSG_KEY_PRESS_WIDE, 		SP1K_MSG_KEY_REPEATE_WIDE, 	SP1K_MSG_KEY_RELEASE_WIDE},

	/*ADC B button msg*/
	{SP1K_MSG_KEY_PRESS_F2, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_F2},
	{SP1K_MSG_KEY_PRESS_PB, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_PB},
	{SP1K_MSG_KEY_PRESS_F1, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_F1},
	{SP1K_MSG_KEY_PRESS_MENU, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_MENU},

	/*GPIO button msg*/
	{SP1K_MSG_KEY_PRESS_POWER, 	SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_POWER},
	{SP1K_MSG_KEY_PRESS_S2, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_S2},

#elif (_HW_SOLUTION_ == _HW_TK_MODEL_A_)

	/*ADC A button msg*/
	{SP1K_MSG_KEY_PRESS_RIGHT,		SP1K_MSG_KEY_REPEATE_RIGHT, 	SP1K_MSG_KEY_RELEASE_RIGHT},
	{SP1K_MSG_KEY_PRESS_LEFT, 		SP1K_MSG_KEY_REPEATE_LEFT, 		SP1K_MSG_KEY_RELEASE_LEFT},
	{SP1K_MSG_KEY_PRESS_DOWN, 	SP1K_MSG_KEY_REPEATE_DOWN, 	SP1K_MSG_KEY_RELEASE_DOWN},
	{SP1K_MSG_KEY_PRESS_UP, 		SP1K_MSG_KEY_REPEATE_UP, 		SP1K_MSG_KEY_RELEASE_UP},
	{SP1K_MSG_KEY_PRESS_TELE, 		SP1K_MSG_KEY_REPEATE_TELE, 		SP1K_MSG_KEY_RELEASE_TELE},
	{SP1K_MSG_KEY_PRESS_WIDE, 		SP1K_MSG_KEY_REPEATE_WIDE, 	SP1K_MSG_KEY_RELEASE_WIDE},

	/*ADC B button msg*/
	{SP1K_MSG_KEY_PRESS_OK, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_OK},
	{SP1K_MSG_KEY_PRESS_PB, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_PB},
	{SP1K_MSG_KEY_PRESS_MENU, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_MENU},

	/*GPIO button msg*/
	{SP1K_MSG_KEY_PRESS_POWER, 	SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_POWER},
	{SP1K_MSG_KEY_PRESS_S2, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_S2},

#elif (_HW_SOLUTION_ == _HW_TK_MODEL_B_)

	/*ADC A button msg*/
	{SP1K_MSG_KEY_PRESS_RIGHT,		SP1K_MSG_KEY_REPEATE_RIGHT, 	SP1K_MSG_KEY_RELEASE_RIGHT},
	{SP1K_MSG_KEY_PRESS_LEFT, 		SP1K_MSG_KEY_REPEATE_LEFT, 		SP1K_MSG_KEY_RELEASE_LEFT},
	{SP1K_MSG_KEY_PRESS_DOWN, 	SP1K_MSG_KEY_REPEATE_DOWN, 	SP1K_MSG_KEY_RELEASE_DOWN},
	{SP1K_MSG_KEY_PRESS_UP, 		SP1K_MSG_KEY_REPEATE_UP, 		SP1K_MSG_KEY_RELEASE_UP},
	{SP1K_MSG_KEY_PRESS_TELE, 		SP1K_MSG_KEY_REPEATE_TELE, 		SP1K_MSG_KEY_RELEASE_TELE},
	{SP1K_MSG_KEY_PRESS_WIDE, 		SP1K_MSG_KEY_REPEATE_WIDE, 	SP1K_MSG_KEY_RELEASE_WIDE},

	/*ADC B button msg*/
	{SP1K_MSG_KEY_PRESS_POWER, 	SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_POWER},
	{SP1K_MSG_KEY_PRESS_OK, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_OK},
	{SP1K_MSG_KEY_PRESS_PB, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_PB},
	{SP1K_MSG_KEY_PRESS_MENU, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_MENU},

	/*GPIO button msg*/
	{SP1K_MSG_NULL, 				SP1K_MSG_NULL, 					SP1K_MSG_NULL},
	{SP1K_MSG_KEY_PRESS_S2, 		SP1K_MSG_NULL, 					SP1K_MSG_KEY_RELEASE_S2},

#endif //hw solution
};

static void battAdcParsing(battUnitAdc_t* pAdc);
static void keyScanAdcParsing(keyUnitAdc_t* pAdc);
static UINT8 keyScanAdcValParsing(UINT16 AdcValue, keyUnitAdc_t* pAdc, UINT8* AdcIdx);
static UINT8 keyScanAdcIdleChk(UINT16 AdcValue, keyUnitAdc_t* pAdc);
static void keyScanGpioParsing(keyUnitGpio_t* pGpio);
static void keyScanGpioValParsing(UINT8 gpioVal, UINT8 gpioChn, keyUnitGpio_t* pGpio, UINT8 gpioPrsFlag);

//static powerBatLv_t xdata BatteryLevel = 0;

static scanTag_t xdata sTag;
static UINT8 xdata sKeyEn[SP1K_BTN_NUM];

#if USE_PKG_DEDICATE_PIN
static UINT8 gpioByteIdS2, gpioBitMskS2;

extern void dedicateGpioCfg(UINT8 pinId, UINT8 *pbyteId, UINT8 *pbitMsk, UINT8 dir);
#endif

//=============================================================================
//Program
//=============================================================================
//-----------------------------------------------------------------------------
//keyScan
//-----------------------------------------------------------------------------
/**
 * @brief		keyScan
 * @param	NONE
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
void keyScan(void)
{
	static UINT8 scanTag = 0;
#if 0//zhenglei
	switch (scanTag) {
		case 0:
#if (_HW_SOLUTION_ != _HW_EVB_)
			battAdcParsing(&sTag.battAdc);
#endif
			//printf("->0\n");
			XBYTE[0x2649] = 0x01;
			scanTag = 0x01;
			break;
		case 1:
			keyScanAdcParsing(&sTag.keyAdcA);
			//printf("->1\n");
			XBYTE[0x2649] = 0x02;
			scanTag = 0x02;
			break;
		case 2:
			keyScanAdcParsing(&sTag.keyAdcB);
			//printf("->2\n");
			XBYTE[0x2649] = 0x00;
			scanTag = 0x00;
			break;
		default:
			break;
	}
#endif
	keyScanGpioParsing(&sTag.keyGpio);
}

//-----------------------------------------------------------------------------
//keyScanGpioValParsing
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanGpioValParsing
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
void keyScanGpioValParsing(UINT8 gpioVal, UINT8 gpioChn, keyUnitGpio_t* pGpio, UINT8 gpioPrsFlag)
{
	UINT8 gpioMsg = SP1K_MSG_NULL;
	UINT8* gpioPreSts = &pGpio->keyAttr[gpioChn].keyStsPrev;

	if (gpioVal != gpioPrsFlag) {
		if (*gpioPreSts == KEY_STATUS_RELEASED) {

			//TODO : idle -> idle : No key action

			return ;
		} else {

			//TODO : Active -> idle : Released

			*gpioPreSts = KEY_STATUS_RELEASED;
			if (*pGpio->keyAttr[gpioChn].pKeyEn & KEY_STATUS_RELEASED) {
				gpioMsg = pGpio->pKeyMsg[gpioChn].keyMsgRls;
			}
		}
	} else {
		if (*gpioPreSts == KEY_STATUS_RELEASED) {

			//TODO : idle -> Active : Pressed

			*gpioPreSts = KEY_STATUS_PRESSED;
			if (*pGpio->keyAttr[gpioChn].pKeyEn & KEY_STATUS_PRESSED) {
				gpioMsg = pGpio->pKeyMsg[gpioChn].keyMsgPrs;
			}
		} else {

			//TODO : Active -> Active : Repeated

			if (*pGpio->keyAttr[gpioChn].pKeyEn & KEY_STATUS_REPEAT) {
				gpioMsg = pGpio->pKeyMsg[gpioChn].keyMsgRpt;
			}
		}
	}

	if (gpioMsg != SP1K_MSG_NULL) {
		osMsgPost(gpioMsg);
	}
}

//-----------------------------------------------------------------------------
//keyScanGpioParsing
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanGpioParsing
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
static void keyScanGpioParsing(keyUnitGpio_t* pGpio)
{
	UINT8 gpioVal;
	UINT8 gpioChn;

#if (_HW_SOLUTION_ == _HW_EVB_ || _HW_SOLUTION_ == _HW_TK_MODEL_A_)

	gpioChn = 0;	// Power

	if (*pGpio->keyAttr[gpioChn].pKeyEn) {
		HAL_GpioByteDirSet(HAL_GPIO_BYTE_GEN1, 0x10, 0x00);  // set gpio[12] as input.
		gpioVal = HAL_GpioByteInGet(HAL_GPIO_BYTE_GEN1, 0x10);

		keyScanGpioValParsing(gpioVal, gpioChn, pGpio, 0x10);
	}
#endif // hw solution

	gpioChn = 1; // S2

	if (*pGpio->keyAttr[gpioChn].pKeyEn) {
		#if USE_PKG_DEDICATE_PIN
		gpioVal = gpioByteInGet(gpioByteIdS2, gpioBitMskS2);
		#else
		XBYTE[0x2D78] |= 0x10;		//Set DGPIO12 as GPIO function
		XBYTE[0x2d75] &= ~0x10;		//DGPIO12
		gpioVal = (XBYTE[0x2dc8] & 0x10);
		#endif

		keyScanGpioValParsing(gpioVal, gpioChn, pGpio, 0x00);
	}
}

//-----------------------------------------------------------------------------
//keyScanInit
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanInit
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
void keyScanInit(void)
{
	scanTag_t* pTag;
	UINT8 i;

	pTag = &sTag;

	for (i = 0; i < SP1K_ADC_BTN_NUM; i++) {
		sKeyEn[i] = 0x00; // set the default key status as disabled
	}

	pTag->keyAdcA.keyActiveIdx = (SP1K_ADC_BTN_A_NUM - 1);
	pTag->keyAdcA.keyAttr.pKeyEn = &sKeyEn[0];
	pTag->keyAdcA.keyAttr.keyNum = SP1K_ADC_BTN_A_NUM;
	pTag->keyAdcA.keyAttr.keyType = KEY_TYPE_ADC_A;
	pTag->keyAdcA.keyCtrl.keyDec = KEY_SCAN_ADC_VAL_DEC;
	pTag->keyAdcA.keyCtrl.keyValRpt = KEY_SCAN_ADC_VAL_RPT_START;
	pTag->keyAdcA.keyCtrl.keyValPrev = KEY_SCAN_ADC_B_VAL_IDLE;
	pTag->keyAdcA.keyCtrl.pKeyDev = &keyAdcAValDevTbl[0];
	pTag->keyAdcA.keyCtrl.pKeyVal = &keyAdcAVal[0];
	pTag->keyAdcA.pKeyMsg = &keyMsg[0];

	pTag->keyAdcB.keyActiveIdx = (SP1K_ADC_BTN_B_NUM - 1);
	pTag->keyAdcB.keyAttr.pKeyEn = &sKeyEn[0 + SP1K_ADC_BTN_A_NUM];
	pTag->keyAdcB.keyAttr.keyNum = SP1K_ADC_BTN_B_NUM;
	pTag->keyAdcB.keyAttr.keyType = KEY_TYPE_ADC_B;
	pTag->keyAdcB.keyCtrl.keyDec = KEY_SCAN_ADC_VAL_DEC;
	pTag->keyAdcB.keyCtrl.keyValRpt = KEY_SCAN_ADC_VAL_RPT_START;
	pTag->keyAdcB.keyCtrl.keyValPrev = KEY_SCAN_ADC_B_VAL_IDLE;
	pTag->keyAdcB.keyCtrl.pKeyDev = &keyAdcBValDevTbl[0];
	pTag->keyAdcB.keyCtrl.pKeyVal = &keyAdcBVal[0];
	pTag->keyAdcB.pKeyMsg = &keyMsg[0 + SP1K_ADC_BTN_A_NUM];

	for (i = 0; i < SP1K_GPIO_BTN_NUM; i++) {
		pTag->keyGpio.keyAttr[i].pKeyEn = &sKeyEn[0 + SP1K_ADC_BTN_NUM];
		pTag->keyGpio.keyAttr[i].keyStsPrev = KEY_STATUS_RELEASED;
	}
	pTag->keyGpio.keyCtrl.keyDec = 1;
	pTag->keyGpio.pKeyMsg = &keyMsg[0 + SP1K_ADC_BTN_NUM];

	#if USE_PKG_DEDICATE_PIN
	dedicateGpioCfg(PKG_DEDICATE_PIN_S2, &gpioByteIdS2, &gpioBitMskS2, 0);
	HAL_GpioByteFuncSet(gpioByteIdS2, gpioBitMskS2, 0xFF);
	#endif
}

//-----------------------------------------------------------------------------
//battDetectCfg
//-----------------------------------------------------------------------------
/**
 * @brief		battDetectCfg
 * @param	UINT8 battLvlTol, UINT16* pBattAdcVal, UINT16 battAdvValDev
 * @retval	NONE
 * @see
 * @author	Phil Lin
 * @since		2008-07-01
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
UINT8 battDetectCfg(UINT8 battLvlTol, UINT16* pBattAdcVal, UINT16 battAdvValDev)
{
	scanTag_t* pTag;

	/*Param check*/
	if (!battLvlTol || pBattAdcVal == NULL) {
		return FAIL;
	}

	pTag = &sTag;

	pTag->battAdc.battLvlTol = battLvlTol;
	pTag->battAdc.pbattAdcVal = pBattAdcVal;
	pTag->battAdc.battAdcDev = battAdvValDev;

	return SUCCESS;
}

//-----------------------------------------------------------------------------
//battDetectInit
//-----------------------------------------------------------------------------
/**
 * @brief		battDetectInit
 * @param	NONE
 * @retval	battery  level
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
UINT8 battDetectInit(void)
{
	scanTag_t* pTag;
	UINT16 adcVal;
	UINT8 i;

	pTag = &sTag;

	XBYTE[0x264c] = 0x01;
	*((UINT8*)&adcVal + 1) = XBYTE[0x264c];
	*((UINT8*)&adcVal + 0) = (XBYTE[0x264d]^0x02);

#if (_HW_SOLUTION_ == _HW_TK_MODEL_B_)
	//ready to check power key
	XBYTE[0x2649] = 0x02;
#endif

	/*the default is lowest level*/
	pTag->battAdc.battLvl  = pTag->battAdc.battLvlTol;

	/*scan the adc value, if no matched, keep the lowest battery level*/
	for (i = 0; i < pTag->battAdc.battLvlTol; i++) {
		if (adcVal >= pTag->battAdc.pbattAdcVal[i]) {
			pTag->battAdc.battLvl = i;
			break;
		}
	}

	pTag->battAdc.battDec = 0;
	pTag->battAdc.battDetectEn = 0;

#if (_HW_SOLUTION_ == _HW_TK_MODEL_B_)
	/*if usb plug in, force battery full*/
	if (sp1kUSB_PlugGet() == USB_PLUG_IN) {
		pTag->battAdc.battLvl = 0;
	}
#endif


#if (_HW_SOLUTION_ == _HW_EVB_) //2008-7-22 mantis #28665
	pTag->battAdc.battLvl = 0;
#endif
	return pTag->battAdc.battLvl;
}

//-----------------------------------------------------------------------------
//sp1kBattEnable
//-----------------------------------------------------------------------------
/**
 * @brief		sp1kBattEnable
 * @param	enable / disable
 * @retval	NONE
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
void sp1kBattEnable(UINT8 enable)
{
	scanTag_t* pTag;

	pTag = &sTag;

	if (enable) {
		pTag->battAdc.battDetectEn = 1;
	} else {
		pTag->battAdc.battDetectEn = 0;
	}
}

//-----------------------------------------------------------------------------
//battAdcParsing
//-----------------------------------------------------------------------------
/**
 * @brief		battAdcParsing
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
static void battAdcParsing(battUnitAdc_t* pAdc)
{
	UINT16 adcVal;
	UINT8 battLv;
	static UINT16 pwrOffRetry = 1;
	UINT16 adcGap;
	UINT8 i;
	UINT8 adcTot;

	if (!pAdc->battDetectEn) {
		return;
	}

	/*capture the adc value*/
	XBYTE[0x264c] = 0x01;
	*((UINT8*)&adcVal + 1) = XBYTE[0x264c];
	*((UINT8*)&adcVal + 0) = (XBYTE[0x264d]^0x02);

	adcGap = pAdc->battAdcDev;
	adcTot = pAdc->battLvlTol;

	battLv = -1;
	for(i = 0; i <= adcTot; i++) {
		if (!i) {
			/* when i == 0;*/
			if (adcVal >= pAdc->pbattAdcVal[i]) {
				battLv = i;
				break;
			}
		} else if (i == adcTot) {
			/*when scan the last value*/
			if (adcVal < pAdc->pbattAdcVal[i - 1] - adcGap) {
				battLv = adcTot;
				break;
			}
		} else {
			if (adcVal >= pAdc->pbattAdcVal[i] && adcVal < pAdc->pbattAdcVal[i - 1] - adcGap) {
				battLv = i;
				break;
			}
		}
	}
	//printf("val(%u)\n", adcVal);

	if (battLv == -1) {
		/*adc value is in gap*/
		//printf("gap!\n");
		return;
	}

	/*If power is in low battery, need be send SP1K_MSG_BAT_LV_UPDATE by cycle */
	if (battLv == adcTot) {

		/*debounds*/
		if (++pAdc->battDec < POWER_BAT_DEC) {
			return;
		}

		/*power off retry*/
		if (!(--pwrOffRetry)) {

			pAdc->battLvl = battLv;
			if (pAdc->battDec) {
				/*restore battdec*/
				--pAdc->battDec;
			}
			pwrOffRetry = BATT_LOW_POWER_OFF_RETRY;
			osMsgPost(SP1K_MSG_BAT_LV_UPDATE);
		}
	} else if (battLv != pAdc->battLvl) {

		/*debounds*/
		if (++pAdc->battDec < POWER_BAT_DEC) {
			return;
		} else {
			/*battery level changed*/
			pAdc->battDec = 0;
			pAdc->battLvl = battLv;
			//printf("->(%bu)\n", pAdc->battLvl);
			osMsgPost(SP1K_MSG_BAT_LV_UPDATE);
		}
	} else {
		/*battery level not changed*/
#ifdef DBG_KEYSCAN
//#if 1
		if (pAdc->battDec) {
			//printf("dec(%bu)\n", pAdc->battDec);
			pAdc->battDec = 0;
		}
#else
		pAdc->battDec = 0;
#endif
	}
}

//-----------------------------------------------------------------------------
//keyScanAdcParsing
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanAdcParsing
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
static void keyScanAdcParsing(keyUnitAdc_t* pAdc)
{
	UINT16 adcVal;
	UINT8 msg = SP1K_MSG_NULL;

	XBYTE[0x264c] = 0x01;//Snap SAR ADC value

	*((UINT8*)&adcVal + 1) = XBYTE[0x264c];
	*((UINT8*)&adcVal + 0) = (XBYTE[0x264d]^0x02);

	if (keyScanAdcIdleChk(adcVal, pAdc) == TRUE) {
		if (keyScanAdcIdleChk(pAdc->keyCtrl.keyValPrev, pAdc) == TRUE) {

			//TODO: Idle -> Idle : No key action

		} else {

			//TODO: Active -> Idle : Key released

			if (pAdc->keyAttr.pKeyEn[pAdc->keyActiveIdx] & KEY_STATUS_RELEASED) {
#ifdef DBG_KEYSCAN
				//CPrintf("==");
				printf("val(%u)\n", adcVal);
				printf("U(%bu)\n", pAdc->keyActiveIdx);
#endif
				//osMsgPost(pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgRls);
				msg = pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgRls;
				pAdc->keyActiveIdx = -1; //key idle
			}
		}

		goto EXIT;
		//pAdc->keyCtrl.keyValPrev = adcVal;
		//return;
	}

	if (keyScanAdcIdleChk(pAdc->keyCtrl.keyValPrev, pAdc) == TRUE) {

		//TODO: Idle  -> Active : Key pressed

		if (keyScanAdcValParsing(adcVal, pAdc, &pAdc->keyActiveIdx) != SUCCESS) {
			//No matched adc value
			goto EXIT;
		}
		if (pAdc->keyAttr.pKeyEn[pAdc->keyActiveIdx] & KEY_STATUS_PRESSED) {
#ifdef DBG_KEYSCAN
			//CPrintf("==");
			printf("val(%u)\n", adcVal);
			printf("D(%bu)\n", pAdc->keyActiveIdx);
#endif
			pAdc->keyCtrl.keyValRpt = KEY_SCAN_ADC_VAL_RPT_START;
			//osMsgPost(pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgPrs);
			msg = pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgPrs;
		}
	} else {

		//TODO: Active -> Active : Key repeated

		if (pAdc->keyAttr.pKeyEn[pAdc->keyActiveIdx] & KEY_STATUS_REPEAT) {
			if  (--pAdc->keyCtrl.keyValRpt == 0) {
				pAdc->keyCtrl.keyValRpt = KEY_SCAN_ADC_VAL_RPT;
				if (pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgRpt != SP1K_MSG_NULL) {
#ifdef DBG_KEYSCAN
					//CPrintf("==");
					printf("val(%u)\n", adcVal);
					printf("R(%bu)\n", pAdc->keyActiveIdx);
#endif
					//osMsgPost(pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgRpt);
					msg = pAdc->pKeyMsg[pAdc->keyActiveIdx].keyMsgRpt;
				}
			}
		}
	}

EXIT:
	pAdc->keyCtrl.keyValPrev = adcVal;

	if (msg != SP1K_MSG_NULL) {
		osMsgPost(msg);
	}
}

//-----------------------------------------------------------------------------
//keyScanAdcValParsing
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanAdcValParsing
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
static UINT8 keyScanAdcValParsing(UINT16 AdcValue, keyUnitAdc_t* pAdc, UINT8* AdcIdx)
{
	UINT8 i;
	UINT8 adcNum = pAdc->keyAttr.keyNum;
	UINT16* pAdcVal = &pAdc->keyCtrl.pKeyVal[0];
	UINT16* pAdcDev = &pAdc->keyCtrl.pKeyDev[0];

	if (pAdc == NULL || AdcIdx == NULL) {
		return FAIL;
	}

	for(i = 0; i < adcNum; i++) {
		if (AdcValue < (*pAdcVal + *pAdcDev)) {
			if (((*pAdcVal > *pAdcDev) && (AdcValue > (*pAdcVal - *pAdcDev))) || \
				((*pAdcVal <= *pAdcDev) && (AdcValue <= (*pAdcVal + *pAdcDev)))) {
				//printf("idx(%bu)\n", i);
				pAdc->keyActiveIdx = i;
				*AdcIdx = i;
				return SUCCESS;
			}
		}
		pAdcVal++;
		pAdcDev++;
	}

	return FAIL;
}

//-----------------------------------------------------------------------------
//keyScanAdcIdleChk
//-----------------------------------------------------------------------------
/**
 * @brief		keyScanAdcIdleChk
 * @param	AdcValue,  pAdc
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
static UINT8 keyScanAdcIdleChk(UINT16 AdcValue, keyUnitAdc_t* pAdc)
{
	if ((pAdc->keyAttr.keyType == KEY_TYPE_ADC_A && AdcValue >= KEY_SCAN_ADC_A_VAL_IDLE) ||
#if (_HW_SOLUTION_ == _HW_EVB_ || _HW_SOLUTION_ == _HW_TK_MODEL_A_)
		(pAdc->keyAttr.keyType == KEY_TYPE_ADC_B && AdcValue >= KEY_SCAN_ADC_B_VAL_IDLE)
#elif (_HW_SOLUTION_ == _HW_TK_MODEL_B_)
		(pAdc->keyAttr.keyType == KEY_TYPE_ADC_B && AdcValue <= KEY_SCAN_ADC_B_VAL_IDLE)
#endif
	) {
		return TRUE;
	} else {
		return FALSE;
	}
}

//-----------------------------------------------------------------------------
//sp1kBtnCfg
//-----------------------------------------------------------------------------
/**
 * @brief		button configure
 * @param	type: Adc A/ Adc B/ Gpio,
			BitMask:
			Enable:
			Bit 0:key press enable
			Bit 1: key release enable
			Bit 2: key repeat enable
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
UINT8 sp1kBtnCfg(keyType_t BtnType, UINT16 BitMask, UINT8 Enable)
{
	UINT8 keyNum;
	UINT8* pKeyEn;
	UINT8 i;

	switch (BtnType) {
		case KEY_TYPE_ADC_A:
			keyNum = SP1K_ADC_BTN_A_NUM;
			pKeyEn = &sKeyEn[0];
			break;
		case KEY_TYPE_ADC_B:
			keyNum = SP1K_ADC_BTN_B_NUM;
			pKeyEn = &sKeyEn[0 + SP1K_ADC_BTN_A_NUM];
			break;
		case KEY_TYPE_GPIO:
			keyNum = SP1K_GPIO_BTN_NUM;
			pKeyEn = &sKeyEn[0 + SP1K_ADC_BTN_NUM];
			break;
		default:
			return FAIL;
	}
/**/
	for (i = 0; i < keyNum; i++) {
		if ((BitMask >> i) & 0x01) {
			*pKeyEn = Enable;
		}
		pKeyEn++;
	}
	//printf("En flag %u\n", *pKeyEn);
	return SUCCESS;
}

//-----------------------------------------------------------------------------
//sp1kAdcHdlGet
//-----------------------------------------------------------------------------
/**
 * @brief		sp1kAdcHdlGet
 * @param
 * @retval	SUCCESS
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
void sp1kAdcHdlGet(const scanTag_t** pAdcHdl)
{
	*pAdcHdl = (const scanTag_t*)&sTag;
}

//-----------------------------------------------------------------------------
//sp1kBtnChk
//-----------------------------------------------------------------------------
/**
 * @brief		check the status of specify button
 * @param
 * @retval	button Status
 			1:KEY_STATUS_PRESSED
 			2:KEY_STATUS_RELEASED
 * @see
 * @author	Phil Lin
 * @since		2008-02-20
 * @todo		Something need to be done.
 * @bug		a bug need to be resolved.
*/
UINT8 sp1kBtnChk(UINT8 button)
{
	UINT8 btnSts;
	UINT8 gpioVal;

	if (button == SP1K_BTN_S2) {
		#if USE_PKG_DEDICATE_PIN
		gpioVal = gpioByteInGet(gpioByteIdS2, gpioBitMskS2);
		#else
		XBYTE[0x2D78] |= 0x10;	//Set DGPIO12 as GPIO function
		XBYTE[0x2d75] &= ~0x10; 	//DGPIO12

		gpioVal = (XBYTE[0x2dc8] & 0x10);
		#endif
		if (!gpioVal) {
			//CPrintf("Press");
			btnSts = KEY_STATUS_PRESSED;
		} else {
			//CPrintf("Release");
			btnSts = KEY_STATUS_RELEASED;
		}
	} else if (button == SP1K_BTN_POWER) {

#if (_HW_SOLUTION_ == _HW_EVB_ || _HW_SOLUTION_ == _HW_TK_MODEL_A_ )
		gpioByteDirSet(GPIO_BYTE_GEN1, 0x10, 0x00);
		if ( !gpioByteInGet(GPIO_BYTE_GEN1, 0x10) ) {
			btnSts = KEY_STATUS_RELEASED;
		} else {
			btnSts = KEY_STATUS_PRESSED;
		}

#elif (_HW_SOLUTION_ == _HW_TK_MODEL_B_)
{
		UINT16 value;

		XBYTE[0x264c] = 0x01;
		*((UINT8*)&value + 1) = XBYTE[0x264c];
		*((UINT8*)&value + 0) = (XBYTE[0x264d]^0x02);
	//	printf("->%u\n", value);

		if((value > (SP1K_ADC_BTN_B_S1 + SP1K_ADC_BTN_DEV_B_S1)) || \
			(value < (SP1K_ADC_BTN_B_S1 - SP1K_ADC_BTN_DEV_B_S1))) {
			btnSts = KEY_STATUS_RELEASED;
		} else {
			btnSts = KEY_STATUS_PRESSED;
		}
}
#endif
	}

	return btnSts;
}

